    // target frames per second
    const FPS = 1;
    const BATTLE = 1;
    //number of radians in segment.
    const NU_SEGMENTS = 7;
    const SEGMENT_RADIANS = (Math.PI*2)/NU_SEGMENTS;
    //needed for preloading
    var PreloadingXML = null;
    var TokensPreloading = 0;
    var TokensPreloaded = 0;

    //needed for drawing
    var canvas = null;
    var buffer = null;
    var C = null;
    var B = null;
    
    var colors = new Array("red", "orange", "yellow", "green", "blue", "indigo", "violet");
    var current_tick = 0;
    
    //var icons = new Array();
    var tokens = new Array();

    window.onload = init;
    
    //stuff for Tokens
    function Token(name, id, defpenalty, bigpicurl, littlepicurl, OnLittleLoad)
    {
        this.name = name;
        this.id = id;
        this.defpenalty = defpenalty;
        this.littlepic = new Image(20,20);
        this.littlepic.onload = OnLittleLoad;
        this.littlepic.src = littlepicurl;
        this.bigpic = new Image(100,100);
        this.bigpic.src = bigpicurl;
    }
    
    function init()
    {
       canvas = document.getElementById('canvas');
       C = canvas.getContext('2d');
       
       //double buffer.
       buffer = document.createElement('canvas');
       buffer.width = canvas.width;
       buffer.height = canvas.height;
       B = buffer.getContext('2d');

       GetBattle(BATTLE);

       //draw();
    }

    function GetBattle(BattleID)
    {
        http=new XMLHttpRequest();
        //set up the callback
        http.onreadystatechange =
                function()
                {
                    if (http.readyState==4)
                    {
                       PreloadTokensThenDrawFromXML(http.responseXML);
                    }
                }
        //set up the request
        var url = "getbattle.php";
        var params = "battleid=" + BattleID;
        http.open("POST", url, true);
        //Send the proper header information along with the request
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        http.overrideMimeType("text/xml");
        //send the request
        http.send(params);
    }

    function NSResolver(prefix)
    {
       return "http://www.gardenofmadness.org";
    }

    function PreloadTokensThenDrawFromXML(xml)
    {
        PreloadingXML = xml;

        //Preload the tokens
        var TokensToLoad = Array();

        var allTokens = xml.getElementsByTagName('token');
        for (var i = 0; i < allTokens.length; i++)
        {
             var tokenID = allTokens[i].getAttribute('id');
             if (tokens[tokenID] == null)
             {
                TokensToLoad.push(tokenID);
             }
        }

        TokensPreloaded = 0;
        TokensPreloading = TokensToLoad.length;
        if (TokensPreloading > 0)
        {
           for (var x = 0; x < TokensToLoad.length; x++)
           {
              GetToken(TokensToLoad[x], BATTLE, DrawCircleIfPreloadFinished);
           }
        }
        else
        {
           DrawCircleFromXML();
        }
    }

    function DrawCircleIfPreloadFinished()
    {
        TokensPreloaded++;
        
        if (TokensPreloading == TokensPreloaded)
        {
            TokensPreloading = 0;
            TokensPreloaded = 0;
            DrawCircleFromXML();
        }
    }

    function DrawCircleFromXML()
    {
        //we're finished preloading
        var xml = PreloadingXML;
        PreloadingXML = null;

        //current tick number.
        var currentTickNum = -1;

        //tokenids on current tick
        var currentTickTokenIDs = new Array();

        //get a list of all of the ticks server should order them for us.
        var tickNodes = xml.getElementsByTagName("t");

        //start drawing.
        WhiteOut(B, 800, 800);
        B.save();
        B.translate(400,300);

        //for each of the tickNodes from the server.
        for (var j = 0; j < tickNodes.length; j++)
        {
            var currentTick = (tickNodes[j].getAttribute('curr') != null);
            if (currentTick)
            {
                    currentTickNum = tickNodes[j].getAttribute('num');
            }
            var tokenNodesOnTick = tickNodes[j].getElementsByTagName('token');
            var tokenIDsOnTick = new Array();
            for (var i = 0; i < tokenNodesOnTick.length; i++)
            {
                tokenIDsOnTick.push(tokenNodesOnTick[i].getAttribute('id'));
                if (currentTick)
                {
                  currentTickTokenIDs.push(tokenNodesOnTick[i].getAttribute('id'));
                }
            }

            B.save();
            //if this is the current tick we need to pop it out.
            if (currentTick)
            {
                B.translate(100 * Math.cos(SEGMENT_RADIANS /2), 100 * Math.sin(SEGMENT_RADIANS /2));
            }
            drawPie(0,0,200, colors[j],  tickNodes[j].getAttribute('num'), currentTick, tokenIDsOnTick);
	    B.restore();
	    B.rotate(SEGMENT_RADIANS);
        }
       B.restore();
       
       C.drawImage(buffer, 0, 0);
       document.getElementById('TickLabel').textContent = "Tick " + currentTickNum;
       for (var x = 0; x < currentTickTokenIDs; x++)
       {
           AddSidebarEntry(tokens[currentTickTokenIDs[x]]);
       }

    }

    function GetToken(TokenID, BattleID, OnLittleLoad)
    {
        http=new XMLHttpRequest();
        //set up the request
        var url = "gettoken.php";
        var params = "battleid=" + BattleID + "&id=" + TokenID;
        http.open("POST", url, false); //this has to be synchronise to get pics
        //Send the proper header information along with the request
        http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        http.overrideMimeType("text/xml");
        //send the request
        http.send(params);
        LoadTokenFromXML(http.responseXML, OnLittleLoad);
    }

    function LoadTokenFromXML(xml, OnLittleLoad)
    {
        var newID = (xml.getElementsByTagName('id'))[0].textContent;
        var newName = (xml.getElementsByTagName('name'))[0].textContent;
        var newPenalty = (xml.getElementsByTagName('defpenalty'))[0].textContent;
        var newBigPic = (xml.getElementsByTagName('bigpic'))[0].textContent;
        var newLittlePic = (xml.getElementsByTagName('littlepic'))[0].textContent;
        
        var newToken = new Token(newName, newID, newPenalty, newBigPic, newLittlePic, OnLittleLoad);
        tokens[newID] = newToken;
    }
    
    function drawNumber(x,y,number,px,reverse)
    {
	B.save();
		B.beginPath();
		B.font = px + 'px sans-serif';
		B.textAlign = "center";
		B.textBaseline="middle";
		var width = B.measureText(number);
		
		
		B.fillStyle = "black";
		if (reverse) B.fillStyle = "white";
		B.strokeStyle = "black";
		if (width > px)
		{
			B.arc(x,y,width, 0, Math.PI * 2, true);
		}
		else
		{
			B.arc(x,y,px, 0, Math.PI * 2, true);
		}
		B.fill();
		B.stroke();
		
		B.beginPath();	
		B.fillStyle = "white";
		if (reverse) B.fillStyle = "black";
		B.fillText(number, x, y);
	B.restore();
    }
    
    function drawPie(x, y, radius, color, tick, current, tokenids)
    {
	var startAngle = 0;
	var endAngle = SEGMENT_RADIANS;
	
	B.save();
		B.strokeStyle="black";
		B.fillStyle=color;
		B.beginPath();		
		B.arc(x, y, radius, startAngle, endAngle, false);			
		B.moveTo(x,y);
		B.lineTo((Math.cos(startAngle) * radius + x), (Math.sin(startAngle) * radius + y));
		B.lineTo((Math.cos(endAngle) * radius + x), (Math.sin(endAngle) * radius + y));
		B.stroke();
		B.fill();
		
		//it's dumb but we have to restroke otherwise we lose half of every line with the fill, and 2/3rds
		//of the last line of the last piece.
		B.beginPath();
		B.moveTo(x,y);
		B.lineTo((Math.cos(endAngle) * radius + x), (Math.sin(endAngle) * radius + y));
		B.stroke();
		
		
		B.save();
		//move us along the center angle that the pie seems to be aligned on.
		B.rotate(startAngle + endAngle / 2);
		//set up icons in pie.
		drawRect(Math.cos(endAngle / 2) * radius / 2, 
                        -1 * (Math.sin(endAngle / 2) * radius / 2),
                        tokenids);
		//number the pie
		drawNumber(radius, 0, tick, 20, current);
		B.restore();
	B.restore();
    }
    
    function drawRect(x1, y2, tokenids)
    {
	drawPics(x1,y2,4,4, tokenids);
    }
    
    function drawPics(x,y,across,down, tokenids)
    {
	B.save();
	B.translate(x,y);
                var tokensDrawn = 0;
		for (row = 0; row < down; row++)
		{
                        if (tokensDrawn == tokenids.length)
                        {
                            break;
                        }
			for (col = 0; col < across; col++)
			{
                                if (tokensDrawn == tokenids.length)
                                {
                                    break;
                                }
				// B.drawImage(icons[0], col * 22, row * 22);
                                B.drawImage(tokens[tokenids[tokensDrawn]].littlepic,
                                            col * 22, row * 22);
                                tokensDrawn++;
			}			
		}
	B.restore();
    }
    
    function WhiteOut(C, height, width)
    {
	C.save();
	C.fillStyle = "rgb(256,256,256)";
	C.fillRect(0,0,height,width);
	C.restore();
    }

    function AddSidebarEntry(token)
    {
        var charsElement = document.getElementById("CharsUp");

        //var picToAdd = document.createElement('img');
        //picToAdd.setAttribute('src',token.bigpic.src);
        //picToAdd.setAttribute('class','charpic')

        var nameToAdd1 = document.createElement('H2');
        nameToAdd1.setAttribute('class', 'charname');
        var nameToAdd2 = document.createTextNode(token.name);
        nameToAdd1.appendChild(nameToAdd2);

        charsElement.appendChild(token.bigpic);
        charsElement.appendChild(nameToAdd1);
    }